﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Text;
using System.Configuration;
using System.Security.Cryptography;
using System.IO;
using System.Text.RegularExpressions;
using System.Globalization;
using Microsoft.Win32;

/// <summary>
/// This class contains all generic AHMIDEA functions
/// </summary>
public class AHMIDEAFunctions
{
    #region Constructor
    public AHMIDEAFunctions() { }
    #endregion Constructor

    #region Context Functions
    /// <summary>
    /// Get POST value based on given key
    /// </summary>
    /// <param name="ctx">Current HTTPContext</param>
    /// <param name="name">Form key name</param>
    /// <returns>Single POST data value</returns>
    public static string ContextPostData(HttpContext ctx, string name)
    {
        string result = "";
        try
        {
            result = ctx.Request.Form.Get(name);
        }
        catch { }
        return result;
    }

    /// <summary>
    /// Get POST values based on given key
    /// </summary>
    /// <param name="ctx">Current HTTPContext</param>
    /// <param name="name">POST key name</param>
    /// <returns>POST data values in array</returns>
    public static string[] ContextPostDataCollection(HttpContext ctx, string name)
    {
        string[] result = new string[]{};
        try
        {
            result = ctx.Request.Form.GetValues(name);
        }
        catch { }
        return result;
    }

    /// <summary>
    /// Retrieve GET value based on given key
    /// </summary>
    /// <param name="ctx">Current HTTPContext</param>
    /// <param name="name">GET key name</param>
    /// <returns>Single GET data value</returns>
    public static string ContextGetData(HttpContext ctx, string name)
    {
        string result = "";
        try
        {
            result = ctx.Request[name];
        }
        catch { }
        return result;
    }

    /// <summary>
    /// Get current username in domain\user format, except for SYSTEM users which only display username. 
    /// </summary>
    /// <param name="ctx">Current HTTP context</param>
    /// <returns>"domain\user" for domain users or just "username" for SYSTEM users</returns>
    public static string ContextUser(HttpContext ctx) {
        return ctx.User.Identity.Name.ToUpper().Replace("SYSTEM\\","").ToLower();
    }

    /// <summary>
    /// Get current domain of logged user
    /// </summary>
    /// <param name="ctx">Current HTTP context</param>
    /// <returns>Domain name</returns>
    public static string ContextDomain(HttpContext ctx) {
        AHMIDEAIdentity id = (AHMIDEAIdentity)ctx.User.Identity;
        return id.Domain;
    }

    public static DateTime? GetDateFromString(string strdate)
    {
        DateTime? dt = null;
        try
        {
            string format = ConfigurationManager.AppSettings["_CONFIG_DATE_FORMAT"];
            dt = DateTime.ParseExact(strdate, format, null, DateTimeStyles.None);
        }
        catch { }
        return dt;
    }

    public static string FormatDate(DateTime date)
    {
        string format = ConfigurationManager.AppSettings["_CONFIG_DATE_FORMAT"];
        return date.ToString(format);
    }

    #endregion Context Functions

    #region Core Functions

    /// <summary>
    /// Generate Main Menu
    /// </summary>
    /// <param name="rewriteCache">Set true to rewrite cache</param>
    /// <returns>HTML menu</returns>
    public static string GenerateMainMenu(bool rewriteCache) {
        StringBuilder sb = new StringBuilder();
        string cachepath = ConfigurationManager.AppSettings["cachePath"];
        string cacheFile = CalculateMD5Hash(HttpContext.Current.User.Identity.Name);
        string cacheFilePath = Path.Combine(cachepath, "MENU_" + cacheFile);
        bool cacheExists = false;
        if (File.Exists(cacheFilePath)) {
            cacheExists = true;
            if (rewriteCache)
            {
                File.Delete(cacheFilePath);
                cacheExists = false;
            }
            else {
                using (var fs = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    using (var sr = new StreamReader(fs, Encoding.Default))
                    {
                        sb.Append(sr.ReadToEnd());
                    }
                }
            }
        }

        if (!cacheExists) {
            string defaultGroupIcon = "icon-arrow-right-3";
            string defaultFormIcon = "";

            sb = new StringBuilder();
            sb.Append("<!--[ROOT]-->");
            using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
            {
                var res = dc.SPAHMIDEA_GetUserMenu(HttpContext.Current.User.Identity.Name);
                string[] mpath;
                string groupIcon;
                string formIcon;
                foreach (SPAHMIDEA_GetUserMenuResult item in res)
                {
                    groupIcon = defaultGroupIcon;
                    formIcon = defaultFormIcon;
                    if (!string.IsNullOrEmpty(item.vgroupicon)) groupIcon = item.vgroupicon;
                    if (!string.IsNullOrEmpty(item.vformicon)) formIcon = item.vformicon;

                    mpath = item.vmenupath.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries);
                    // application title
                    if (!sb.ToString().Contains("<!--[" + item.vappid + "]-->")) {
                        sb.Replace("<!--[ROOT]-->", "<li data-group=\"" + item.vappid + "\" class=\"title bg-darkCyan fg-white\"><span>" + item.vapptitle + "</span></li><!--[APP:" + item.vappid + "]--><!--[" + item.vappid + "]--><!--[ROOT]-->");
                    }

                    // application menu
                    for (int i = 0; i < mpath.Length; i++)
                    {
                        if ((i == 0) && (!sb.ToString().Contains("<!--[FRM:" + mpath[i] + "]-->")))
                        {
                            sb.Replace("<!--[APP:" + item.vappid + "]-->", "<li data-group=\"" + item.vappid + "\"><a class=\"dropdown-toggle\" href=\"#\"><i class=\""+groupIcon+"\"></i>" + mpath[i] + "</a><ul class=\"dropdown-menu\" data-role=\"dropdown\"><!--[DTL:" + mpath[i] + "]--></ul><!--[FRM:" + mpath[i] + "]--><!--[APP:" + item.vappid + "]-->");
                        }

                        if ((i > 0) && (sb.ToString().Contains("<!--[DTL:" + mpath[i-1] + "]-->")))
                        {
                            sb.Replace("<!--[DTL:" + mpath[i - 1] + "]-->", "<li  data-group=\"" + mpath[i - 1] + "\"><a href=\"" + item.vformpath + "\" data-appid=\""+item.vappid+"\" data-fid=\""+item.vformid+"\" data-formid=\"" + item.vappid + '-' + item.vformid + "\" data-form-icon=\""+formIcon+"\" >" + item.vformtitle + "</a></li><!--[DTL:" + mpath[i - 1] + "]-->");
                        }
                        
                    }
                }
            }

            using (StreamWriter sw = new StreamWriter(cacheFilePath, true))
            {
                sw.WriteLine(sb.ToString());
                sw.Close();
            }

        }

        return sb.ToString();
    }

    #endregion Core Functions

    #region Form Functions

    /// <summary>
    /// Get a global Form header
    /// </summary>
    /// <param name="appid">Application ID</param>
    /// <param name="formid">Form ID</param>
    /// <returns>HTML form header</returns>
    public static string GetFormHeader(string appid, string formid)
    {
        string title = "";
        int state = 0;
        int fav = 0;
        StringBuilder sbBread = new StringBuilder();
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = dc.AHMIDEA_MSTFORMs.FirstOrDefault(t => (t.vappid == appid) && (t.vformid == formid));

            title = i.vformtitle;
            string[] sba = i.vmenupath.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries);
            if (sba.Length > 0)
            {
                sbBread.Append("<nav class=\"breadcrumbs no-phone mini\"><ul>");
                for (int x = 0; x < sba.Length; x++)
                {
                    if (x + 1 >= sba.Length)
                    {
                        sbBread.Append("<li class=\"active\"><a>" + sba[x] + "</a></li>");
                    }
                    else
                    {
                        sbBread.Append("<li><a>" + sba[x] + "</a></li>");
                    }
                }
                sbBread.Append("</ul></nav>");
            }

            // savestates
            string user = ContextUser(HttpContext.Current);
            var j = (from t in dc.AHMIDEA_DTLPROFILEs where ((t.vuserid == user) && (t.vappid == appid) && (t.vformid == formid) && (t.itype == 3)) select t).FirstOrDefault();
            if (j != null)
            {
                state = 1;
            }
            // favorites
            var k = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 2) select t).FirstOrDefault();
            if (k != null)
            {
                fav = 1;
            }

        }

        string fstate = state == 0 ? "<button class=\"info large\" title=\"Save Draft\" onclick=\"_fw_formSaveDraft(this)\" ><span class=\"icon-bookmark-2\"></span></button>" : "<button class=\"info large\" title=\"Open Draft\" onclick=\"_fw_formOpenDraft(this)\"><span class=\"icon-bookmark\"></span></button>";
        string ffav = fav == 0 ? "<button class=\"info large\" title=\"Set Favorite\" onclick=\"_fw_formSetFavorite(this)\" ><span class=\"icon-star\"></span></button>" : "<button class=\"info large\" title=\"Remove Favorite\" onclick=\"_fw_formUnsetFavorite(this)\" ><span class=\"icon-star-3\"></span></button>";

        return @"<div class=""toolbar""> 
        <button class=""warning large"" onclick=""_fw_formReloadCurrent(this)"" title=""Refresh""><span class=""icon-cycle""></span></button>
        " + fstate + ffav + @"
        </div>
        <h1><a href=""#"" onclick=""_fw_setTabOpenHome(); return false;""><i class=""icon-arrow-left-3 fg-darker smaller""></i></a>
        " + title + @"</h1>" + sbBread.ToString() + @"<div class=""message-box""></div>";
    }

    public static string CheckFormState(HttpContext context, string appid, string formid)
    {
        string state = "0";
        string fav = "0";
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            // savestates
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 3) select t).FirstOrDefault();
            if (i != null)
            {
                state = "1";
            }
            // favorites
            var j = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 2) select t).FirstOrDefault();
            if (j != null)
            {
                fav = "1";
            }
        }
        return "{\"state\":\"" + state + "\", \"favs\":\"" + fav + "\"}";
    }

    public static string GetFormState(HttpContext context, string appid, string formid)
    {
        string state = "";
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 3) select t).FirstOrDefault();
            if (i != null)
            {
                state = i.vuserdata;
                dc.AHMIDEA_DTLPROFILEs.DeleteOnSubmit(i);
                dc.SubmitChanges();
            }
        }
        return state;
    }

    public static AjaxResponse SaveFormState(HttpContext context, string appid, string formid, string stateData)
    {
        AjaxResponse axresp = new AjaxResponse();
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 3) select t);
            bool found = false;
            foreach (var item in i)
            {
                found = true;
                item.vuserdata = HttpUtility.UrlDecode(stateData);
            }
            if (!found)
            {
                AHMIDEA_DTLPROFILE dp = new AHMIDEA_DTLPROFILE();
                dp.vuserid = user;
                dp.vappid = appid;
                dp.vformid = formid;
                dp.itype = 3;
                dp.vuserdata = HttpUtility.UrlDecode(stateData);
                dp.dcrea = DateTime.Now;

                dc.AHMIDEA_DTLPROFILEs.InsertOnSubmit(dp);
            }
            dc.SubmitChanges();
        }
        axresp.Status = "1";
        
        return axresp;
    }

    public static AjaxResponse DeleteFormState(HttpContext context, string appid, string formid)
    {
        AjaxResponse axresp = new AjaxResponse();
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 3) select t);
            dc.AHMIDEA_DTLPROFILEs.DeleteAllOnSubmit(i);
            dc.SubmitChanges();
        }
        axresp.Status = "1";
        return axresp;
    }

    public static AjaxResponse SaveFormFavorite(HttpContext context, string appid, string formid)
    {
        AjaxResponse axresp = new AjaxResponse();
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 2) select t).FirstOrDefault();
            if (i == null)
            {
                AHMIDEA_DTLPROFILE dp = new AHMIDEA_DTLPROFILE();
                dp.vuserid = user;
                dp.vappid = appid;
                dp.vformid = formid;
                dp.itype = 2;
                dp.dcrea = DateTime.Now;

                dc.AHMIDEA_DTLPROFILEs.InsertOnSubmit(dp);
                dc.SubmitChanges();
            }
        }
        axresp.Status = "1";
        return axresp;
    }

    public static AjaxResponse DeleteFormFavorite(HttpContext context, string appid, string formid)
    {
        AjaxResponse axresp = new AjaxResponse();
        string user = ContextUser(context);
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = (from t in dc.AHMIDEA_DTLPROFILEs where (t.vuserid == user && t.vappid == appid && t.vformid == formid && t.itype == 2) select t);
            dc.AHMIDEA_DTLPROFILEs.DeleteAllOnSubmit(i);
            dc.SubmitChanges();
        }
        axresp.Status = "1";
        return axresp;
    }

    public static Boolean IsFunctionAuthorized(HttpContext context, string appId, string vformid, string funcId) {
        bool authorized = false;
        using (DC_AHMIDEADataContext dc = new DC_AHMIDEADataContext())
        {
            var i = dc.VW_AHMIDEA_USERPERMISSIONs.FirstOrDefault(u => u.vappid == appId && u.vformid==vformid && u.vfuncid == funcId && u.vuserid == ContextUser(context));
            authorized = (i != null); 
        }
        return authorized;
    }

    public static string GetFormNotAuthorizedHeader() {
        return "<h1 class=\"fg-crimson\"><i class=\"icon-warning\"></i> Error 401</h1><div class=\"message\">Sorry, you are not authorized to view this form.</div>";
    }
    public static AjaxResponse NotAuthorizedResponse()
    {
        return new AjaxResponse() { Status = "0", Message = "Sorry, you are not authorized to do this task." };
    }

    public static AjaxResponse InvalidRequestResponse()
    {
        return new AjaxResponse() { Status = "0", Message = "Invalid request." };
    }

    public static string UploadFile(HttpContext ctx, string basePath, bool clearBeforeUpload)
    {
        string fn = "";
        if ((ctx.Request.Files.Count > 0) && (ctx.Request.Files[0].ContentLength > 0))
        {
            AHMIDEAIdentity user = (AHMIDEAIdentity)ctx.User.Identity;
            string userFolder = Encryption.MD5Hash(user.Domain + "\\" + user.Username);

            HttpPostedFile file = ctx.Request.Files[0];
            string ext = System.IO.Path.GetExtension(file.FileName);
            fn = Guid.NewGuid().ToString() + ext;
            string path = Path.Combine(HttpContext.Current.Server.MapPath(basePath), ConfigurationManager.AppSettings["_CONFIG_UPLOAD_PATH"]);
            path = Path.Combine(path, userFolder);
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);

            if (clearBeforeUpload) {
                string[] files = Directory.GetFiles(path);
                foreach (string item in files)
                {
                    File.Delete(item);
                }
            }

            path = Path.Combine(path, fn);
            file.SaveAs(path);
        }
        return fn;
    }

    public static string UploadFile(HttpContext ctx)
    {
        return UploadFile(ctx,"../../../", true);
    }

    public static string GetUploadedFilePath(HttpContext ctx, string basePath, string fileId) {
        AHMIDEAIdentity user = (AHMIDEAIdentity)ctx.User.Identity;
        string userFolder = Encryption.MD5Hash(user.Domain + "\\" + user.Username);
        string path = Path.Combine(HttpContext.Current.Server.MapPath(basePath), ConfigurationManager.AppSettings["_CONFIG_UPLOAD_PATH"]);
        path = Path.Combine(path, userFolder);
        if (!Directory.Exists(path)) Directory.CreateDirectory(path);
        path = Path.Combine(path, fileId);
        if (File.Exists(path)) return path;
        else return string.Empty;
    }

    public static string GetUploadedFilePath(HttpContext ctx, string fileId)
    {
        return GetUploadedFilePath(ctx, "../../../", fileId);
    }

    #endregion Form Functions

    #region Tools

    /// <summary>
    /// Get MD5 Hash from a string
    /// </summary>
    /// <param name="input">string input</param>
    /// <returns>MD5 Hash</returns>
    public static string CalculateMD5Hash(string input)
    {
        // step 1, calculate MD5 hash from input
        MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
        byte[] hash = md5.ComputeHash(inputBytes);

        // step 2, convert byte array to hex string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }

    /// <summary>
    /// Get default extension from given mime type
    /// </summary>
    /// <param name="mimeType">mime type</param>
    /// <returns>default file extension</returns>
    public static string GetDefaultExtension(string mimeType)
    {
        string result;
        RegistryKey key;
        object value;

        key = Registry.ClassesRoot.OpenSubKey(@"MIME\Database\Content Type\" + mimeType, false);
        value = key != null ? key.GetValue("Extension", null) : null;
        result = value != null ? value.ToString() : string.Empty;

        return result;
    }

    #endregion Tools
}

